package com.zzy.ymcc.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;

import com.zzy.ymcc.constants.RedisSmsConstants;
import com.zzy.ymcc.domain.Login;
import com.zzy.ymcc.domain.User;
import com.zzy.ymcc.domain.UserAccount;
import com.zzy.ymcc.domain.UserBaseInfo;
import com.zzy.ymcc.dto.PhoneRegisterDto;
import com.zzy.ymcc.dto.RedisSmsDto;
import com.zzy.ymcc.enums.GlobalExceptionCode;
import com.zzy.ymcc.feign.LoginService;
import com.zzy.ymcc.mapper.UserMapper;
import com.zzy.ymcc.result.JSONResult;
import com.zzy.ymcc.service.IUserAccountService;
import com.zzy.ymcc.service.IUserBaseInfoService;
import com.zzy.ymcc.service.IUserService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.zzy.ymcc.util.AssertUtil;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author director
 * @since 2022-09-23
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private LoginService loginService;

    @Autowired
    private IUserBaseInfoService userBaseInfoService;

    @Autowired
    private IUserAccountService userAccountService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(PhoneRegisterDto phoneRegisterDto) {
        String mobile = phoneRegisterDto.getMobile();
        Integer regChannel = phoneRegisterDto.getRegChannel();
        String smsCode = phoneRegisterDto.getSmsCode();
        // 1.参数校验使用JSR 303 完成
        // 2.拼接业务键，去redis中获取短信验证码，进行校验
        String redisKey = String.format(RedisSmsConstants.REDIS_REGISTER_PHONE_KEY, mobile);
        Object obj = redisTemplate.opsForValue().get(redisKey);
        // 2.1.如果短信验证码为空，那么抛出异常
        AssertUtil.isNotNull(obj, GlobalExceptionCode.VERIFY_IS_EMPTY);
        // 2.2.判断短信验证码是否正确
        RedisSmsDto redisSmsDto = (RedisSmsDto) obj;
        AssertUtil.isEquals(smsCode, redisSmsDto.getCode(), GlobalExceptionCode.VERIFY_IS_ERROR);
        // 3.根据手机号查询用户信息
        User user = selectUser(mobile);
        // 3.1.判断用户是否已注册
        AssertUtil.isNull(user, GlobalExceptionCode.USER_EXISTED_ERROR);
        // 4.保存login
        JSONResult jsonResult = saveLogin(phoneRegisterDto);
        // 4.1.断言jsonResult是否成功
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalExceptionCode.USER_SAVE_ERROR);
        // 4.2.断言ID是否为null
        AssertUtil.isNotNull(jsonResult.getData(), GlobalExceptionCode.USER_SAVE_ERROR);
        // 4.3.得到id
        Long loginId = Long.valueOf(jsonResult.getData().toString());
        System.out.println(111);
        // 5.保存user相关表
        // 手动制造错误
//        int i = 1/0;
//        System.out.println(i);
        // 5.1.保存用户信息
        Long userId = saveUser(loginId, phoneRegisterDto);
        System.out.println(222);
        // 5.2.保存用户基本信息
        initUserBaseInfo(userId, regChannel);
        // 5.3.保存用户账号信息
        initUserAccount(userId);
    }

    // 保存用户基础信息
    private void initUserBaseInfo(Long userId, Integer regChannel) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(userId);
        userBaseInfo.setRegChannel(regChannel);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfoService.insert(userBaseInfo);
    }

    // 初始化用户账户信息
    private void initUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setCreateTime(new Date().getTime());
        userAccount.setPassword("123456"); // 默认密码要抽出来，发送短信告知用户默认密码 @TODO
        userAccount.setId(userId);
        userAccount.setFrozenAmount(new BigDecimal(0));
        userAccount.setUsableAmount(new BigDecimal(0));
        userAccountService.insert(userAccount);
    }

    // 保存用户信息
    private Long saveUser(Long loginId, PhoneRegisterDto phoneRegisterDto) {
        User user = new User();
        user.setCreateTime(new Date().getTime());
        user.setLoginId(loginId);
        user.setNickName(phoneRegisterDto.getMobile());
        user.setPhone(phoneRegisterDto.getMobile());
        insert(user);
        return user.getId();
    }

    // 保存login
    private JSONResult saveLogin(PhoneRegisterDto phoneRegisterDto) {
        Login login = new Login();
        login.setUsername(phoneRegisterDto.getMobile());
        login.setPassword(phoneRegisterDto.getPassword());
        login.setType(Login.USER_TYPE);
        login.setEnabled(Login.ENABLE);
        return loginService.saveOrUpdate(login);
    }

    // 根据电话号码查询用户信息
    private User selectUser(String mobile) {
        // 1.创建user对象的条件构造器
        Wrapper<User> wrapper = new EntityWrapper<>();
        // 2.设置查询条件  select * from t_user where phone = #{mobile};
        wrapper.eq("phone", mobile);
        // 2.根据条件构造器，调用父类方法进行查询，条件构造器泛型给的是什么返回值就是什么
        return selectOne(wrapper);
    }
}

